﻿//#define INT_MAIN
//#define MAIN_PARAMS_KEYWORD
#define MAIN_STRING_ARGS

using System;
using System.Threading;

namespace TrazandoAndo
{
    struct FormalParam<T>
    {
        public string   name;
        public T        val;
    }

    class Program
    {
        static bool _pararAlFinal = false;
        static int  x       = 5;

        // esto es al pedo pero me encanta el poder de las macros.
        // c# no tiene buenas macros como c, pero por lo menos
        // admiten la compilación condicional.

        static
        #if INT_MAIN
            int
        #else
            void
        #endif
        Main (
            #if MAIN_STRING_ARGS
                #if MAIN_PARAMS_KEYWORD
                    params
                #endif
                string [] args
            #endif

            //// código aplanado...
            //#if MAIN_STRING_ARGS && MAIN_PARAMS_KEYWORD
            //    params string [] args
            //#elif MAIN_STRING_ARGS
            //    string [] args
            //#else
            //    /* epsilon */
            //#endif
        )
        {
            Console.WriteLine( x.ToString() ) ;
            Console.WriteLine( x.GetType().ToString() );

            Tracer.enterMethod("Main");

            if (args.Length > 0 && args[0] == "stop")
                _pararAlFinal = true;

            int start = Environment.TickCount;

            for (int i = 0; i < 1e1; ++i)
                trabajar();

            Tracer.exitMethod("Main", ExitType.RETURN);

            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("{0} milis", Environment.TickCount - start);
            Console.WriteLine("{0} llamadas", Tracer.calls);

            if (_pararAlFinal)
                Console.ReadLine();

            #if INT_MAIN
                return 0;
            #endif
        }

        public char graciasDonCSharpo <T>(T t) {
            t.GetType();
            t.ToString();
            return 'c';
        }

        public void gracias<P1, P2>(FormalParam<P1> p1, FormalParam<P2> p2)
        {
            p1.val.ToString();
            p2.val.ToString();
        }

        private static void trabajar()
        {
            Tracer.enterMethod("trabajar");

            for (int i = 0; i < 3; ++i)
                pipo();

            Tracer.exitMethod("trabajar", ExitType.RETURN);
        }

        static int pipo()
        {
            Tracer.enterMethod("pipo");

            int ret = pope() + pope() + pope();

            Tracer.exitMethod("pipo", ExitType.RETURN);
            return ret;
        }

        static int pope()
        {
            Tracer.enterMethod("pope");

            //x--;              // <-
            int ret = 17 / x;   // <- fuerzo un error de división por 0

            Tracer.exitMethod("pope", ExitType.RETURN);
            return ret;
        }
    }
}
